package scene;

import raytracer.IntersectionResult;
import raytracer.Ray;
import raytracer.Vector3f;

public class Triangle extends Shape {
	private static int nextId;
	public int id = nextId++;

	// / The vertices of the triangle.
	public Vector3f[] verts;
	public Vector3f u;
	public Vector3f v;

	// / The material of the triangle.
	public Material material;

	public Vector3f normal;

	// / Create a triangle with the specified vertices and material.
	public Triangle(Vector3f v1, Vector3f v2, Vector3f v3, Material m) {
		if (v1 == null || v1 == null || v2 == null || m == null)
			throw new NullPointerException();

		verts = new Vector3f[3];
		verts[0] = v1;
		verts[1] = v2;
		verts[2] = v3;
		material = m;

		u = this.verts[1].subtract(verts[0]);
		v = this.verts[2].subtract(verts[0]);
		this.normal = u.cross(v).normalize();
	}

	@Override
	public String toString() {
		return "Tri" + id + " " + verts[0] + " " + verts[1] + " " + verts[2] + " n" + normal + " mat:" + material;
	}

	public IntersectionResult intersect(Ray ray) {
		// Algorithm from
		// http://softsurfer.com/Archive/algorithm_0105/algorithm_0105.htm
		// if(Math.abs(0) == 0) return null;

		if (normal.isZero()) {
			return null;
		}

		float cosv = normal.dot(ray);
		if (cosv > 0f) {
			// Degenerate triangle
			normal.negateLocal();
		}

		Vector3f w0 = ray.start.subtract(verts[0]);
		float a = -normal.dot(w0);
		float b = normal.dot(ray);
		if (Math.abs(b) < 0.000001f) {
			// Ray is parallel to triangle
			return null;
		}

		float r = a / b;
		if (r < 0f ) {
			// Ray goes away from triangle
			return null;
		}

		Vector3f i = ray.start.add(ray.scale(r));

		float uu = u.dot(u);
		float uv = u.dot(v);
		float vv = v.dot(v);
		Vector3f w = i.subtract(verts[0]);
		float wu = w.dot(u);
		float wv = w.dot(v);
		float d = uv * uv - uu * vv;

		float s = (uv * wv - vv * wu) / d;
		if (s < 0f || s > 1f) {
			return null;
		}
		float t = (uv * wu - uu * wv) / d;
		if (t < 0f || (s + t) > 1f) {
			return null;
		}

		return new IntersectionResult(i, new Vector3f(normal), material, r, this);

	}

	public String getName() {
		return "Tri" + id;
	}

}
